package com.alogic.remote.xscript.auth;

import com.alogic.remote.Request;
import com.alogic.remote.xscript.RequestHandler;
import com.alogic.xscript.ExecuteWatcher;
import com.alogic.xscript.Logiclet;
import com.alogic.xscript.LogicletContext;
import com.alogic.xscript.doc.XsObject;
import com.anysoft.util.Properties;
import com.anysoft.util.PropertiesConstants;
import com.anysoft.util.code.Coder;
import com.anysoft.util.code.CoderFactory;
import org.apache.commons.lang3.StringUtils;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 增加Signature方式的验证头
 *
 * @since 1.6.12.41 [20190902] <br>
 *
 * @version 1.6.12.50 [20191204] <br>
 * - 修正URL取值的问题
 */
public class WithSignature extends RequestHandler {

    protected static String timestampId = "x-alogic-now";
    protected static String payloadId = "x-alogic-payload";
    protected static String signatureId = "x-alogic-signature";
    protected static String keyId = "x-alogic-app";
    protected static String acGroupKeyId = "x-alogic-ac";
    protected static String acGroup = "app";
    protected Coder coder = null;

    /**
     * 应用id
     */
    protected String $key="";

    /**
     * 密钥
     */
    protected String $keyContent="";

    /**
     * 本次访问的Url
     */
    protected String $url;

    /**
     * payload的签名信息
     */
    protected String $payload;

    /**
     * 匹配完整url的表达式
     */
    protected static Pattern pattern = Pattern.compile("(\\w+):\\/\\/([^/:]+)(?::(\\d*))?(.*)");

    public WithSignature(String tag, Logiclet p) {
        super(tag, p);
    }

    @Override
    public void configure(Properties p){
        super.configure(p);

        $key = PropertiesConstants.getRaw(p,"key",$key);
        $keyContent = PropertiesConstants.getRaw(p,"keyContent",$keyContent);
        $url = PropertiesConstants.getRaw(p,"url","");
        $payload = PropertiesConstants.getRaw(p,"payload","");
        coder = CoderFactory.newCoder(PropertiesConstants.getString(p,"coder", "HmacSHA256"));
    }

    @Override
    protected void onExecute(final Request req, final XsObject root, final XsObject current, final LogicletContext ctx,
                             final ExecuteWatcher watcher) {

        String uriPath = getUriPath(PropertiesConstants.transform(ctx,$url,""));
        if (StringUtils.isNotEmpty(uriPath)) {
            String now = String.valueOf(System.currentTimeMillis());
            String key = PropertiesConstants.transform(ctx,$key,"");
            StringBuffer toSign = new StringBuffer();
            toSign.append(key).append("\n");
            toSign.append(now).append("\n");
            toSign.append(uriPath);
            String payload = PropertiesConstants.transform(ctx,$payload,"");
            if (StringUtils.isNotEmpty(payload)) {
                toSign.append("\n").append(payload);
            }
            String signature = coder.encode(toSign.toString(), PropertiesConstants.transform(ctx,$keyContent,""));
            if (StringUtils.isNotEmpty(signature)) {
                req.setHeader(signatureId, signature);
                req.setHeader(timestampId, now);
                req.setHeader(keyId, key);
                req.setHeader(acGroupKeyId, acGroup);
            }
        }
    }

    protected static String getUriPath(String urlPath){
        Matcher matcher = pattern.matcher(urlPath);
        if (matcher.find()){
            return matcher.group(4);
        }else{
            return urlPath;
        }
    }
}